# -*- coding: utf-8 -*-
"""
DTM验证工具 - 主控制器模块
负责协调各个模块，实现主要业务逻辑
"""

import os
from typing import List, Dict, Any, Optional, Callable
from datetime import datetime

# 导入自定义模块
from config_manager import ConfigManager, FileConfig, Constants
from data_processor import BatchDataProcessor, ExcelDataProcessor
from geometry_calculator import GeometryAnalyzer
from visualizer import VisualizationManager
from file_manager import FilePathManager, FileValidator, DirectoryScanner


class DTMController:
    """DTM验证工具主控制器"""

    def __init__(self, project_root: Optional[str] = None):
        # 初始化各个组件
        self.config_manager = ConfigManager()
        self.file_path_manager = FilePathManager(project_root)
        self.data_processor = BatchDataProcessor()
        self.geometry_analyzer = GeometryAnalyzer()
        self.visualization_manager = VisualizationManager(
            self.file_path_manager.get_output_directory()
        )
        self.file_validator = FileValidator()
        self.directory_scanner = DirectoryScanner()

        # 状态管理
        self.processing_status = "idle"  # idle, processing, completed, error
        self.current_batch_results: List[Dict[str, Any]] = []
        self.log_messages: List[str] = []

        # 回调函数（用于GUI更新）
        self.progress_callback: Optional[Callable[[int, int], None]] = None
        self.status_callback: Optional[Callable[[str], None]] = None
        self.log_callback: Optional[Callable[[str], None]] = None

    def set_callbacks(
        self,
        progress_callback: Optional[Callable[[int, int], None]] = None,
        status_callback: Optional[Callable[[str], None]] = None,
        log_callback: Optional[Callable[[str], None]] = None,
    ):
        """设置回调函数"""
        self.progress_callback = progress_callback
        self.status_callback = status_callback
        self.log_callback = log_callback

    def add_file(self, file_path: str, fixed_height: float) -> bool:
        """
        添加文件到处理队列

        Args:
            file_path: 文件路径
            fixed_height: 基准高程

        Returns:
            bool: 添加是否成功
        """
        try:
            # 验证文件
            validation_result = self.file_validator.validate_excel_file(file_path)
            if not validation_result["is_valid"]:
                self._log(
                    f"文件验证失败: {file_path} - {validation_result['error_message']}"
                )
                return False

            # 添加到配置管理器
            self.config_manager.add_file_config(file_path, fixed_height)
            self._log(
                f"已添加文件: {os.path.basename(file_path)}, 基准高程: {fixed_height}"
            )
            return True

        except Exception as e:
            self._log(f"添加文件失败: {str(e)}")
            return False

    def add_files_from_directory(
        self, directory_path: str, default_height: float, recursive: bool = False
    ) -> int:
        """
        从目录添加Excel文件

        Args:
            directory_path: 目录路径
            default_height: 默认基准高程
            recursive: 是否递归扫描

        Returns:
            int: 成功添加的文件数量
        """
        excel_files = self.directory_scanner.scan_directory_for_excel_files(
            directory_path, recursive
        )

        added_count = 0
        for file_path in excel_files:
            if self.add_file(file_path, default_height):
                added_count += 1

        self._log(
            f"从目录扫描到 {len(excel_files)} 个Excel文件，成功添加 {added_count} 个"
        )
        return added_count

    def remove_file(self, file_path: str) -> bool:
        """移除文件配置"""
        success = self.config_manager.remove_file_config(file_path)
        if success:
            self._log(f"已移除文件: {os.path.basename(file_path)}")
        return success

    def clear_files(self) -> None:
        """清空所有文件配置"""
        self.config_manager.clear_file_configs()
        self._log("已清空所有文件配置")

    def get_file_list(self) -> List[Dict[str, Any]]:
        """获取当前文件列表信息"""
        file_list = []
        for config in self.config_manager.file_configs:
            validation_result = self.file_validator.validate_excel_file(
                config.file_path
            )
            file_list.append(
                {
                    "file_path": config.file_path,
                    "fixed_height": config.fixed_height,
                    "is_valid": validation_result["is_valid"],
                    "file_size": validation_result["file_size"],
                    "error_message": validation_result.get("error_message", ""),
                }
            )
        return file_list

    def process_batch(self) -> Dict[str, Any]:
        """
        执行批量处理

        Returns:
            Dict[str, Any]: 处理结果汇总
        """
        try:
            # 检查状态
            if self.processing_status == "processing":
                raise RuntimeError("正在处理中，请等待完成")

            # 获取有效的文件配置
            valid_configs = self.config_manager.get_valid_file_configs()
            if not valid_configs:
                raise ValueError("没有有效的文件需要处理")

            self._update_status("processing")
            self._log(f"开始批量处理 {len(valid_configs)} 个文件")

            # 重置结果
            self.current_batch_results.clear()

            # 处理每个文件
            for i, config in enumerate(valid_configs):
                try:
                    self._update_progress(i, len(valid_configs))
                    self._log(f"正在处理: {os.path.basename(config.file_path)}")

                    result = self._process_single_file(
                        config.file_path, config.fixed_height
                    )
                    self.current_batch_results.append(result)

                    if result["success"]:
                        self._log(f"处理完成: {os.path.basename(config.file_path)}")
                    else:
                        self._log(
                            f"处理失败: {os.path.basename(config.file_path)} - {result['error']}"
                        )

                except Exception as e:
                    error_result = {
                        "file_path": config.file_path,
                        "success": False,
                        "error": str(e),
                        "analysis_result": None,
                    }
                    self.current_batch_results.append(error_result)
                    self._log(
                        f"处理异常: {os.path.basename(config.file_path)} - {str(e)}"
                    )

            # 更新进度到100%
            self._update_progress(len(valid_configs), len(valid_configs))

            # 生成可视化和报告
            self._log("生成可视化图像和报告...")
            visualization_files = (
                self.visualization_manager.process_visualization_batch(
                    self.current_batch_results
                )
            )

            report_files = self.visualization_manager.generate_comprehensive_report(
                self.current_batch_results, self.log_messages
            )

            # 计算汇总统计
            summary = self._calculate_batch_summary()

            self._update_status("completed")
            self._log("批量处理完成！")

            return {
                "success": True,
                "summary": summary,
                "results": self.current_batch_results,
                "visualization_files": visualization_files,
                "report_files": report_files,
                "log_messages": self.log_messages.copy(),
            }

        except Exception as e:
            self._update_status("error")
            self._log(f"批量处理失败: {str(e)}")
            return {
                "success": False,
                "error": str(e),
                "summary": None,
                "results": self.current_batch_results,
                "log_messages": self.log_messages.copy(),
            }

    def _process_single_file(
        self, file_path: str, fixed_height: float
    ) -> Dict[str, Any]:
        """处理单个文件"""
        try:
            # 数据处理
            data_result = self.data_processor.process_single_file(
                file_path, fixed_height
            )

            if not data_result["success"]:
                return {
                    "file_path": file_path,
                    "success": False,
                    "error": data_result["error"],
                    "analysis_result": None,
                }

            # 几何分析
            vertices = data_result["vertices"]
            analysis_result = self.geometry_analyzer.comprehensive_analysis(
                vertices, fixed_height
            )

            return {
                "file_path": file_path,
                "success": True,
                "error": None,
                "analysis_result": analysis_result,
                "data_statistics": data_result["statistics"],
            }

        except Exception as e:
            return {
                "file_path": file_path,
                "success": False,
                "error": str(e),
                "analysis_result": None,
            }

    def _calculate_batch_summary(self) -> Dict[str, Any]:
        """计算批量处理汇总信息"""
        successful_results = [r for r in self.current_batch_results if r["success"]]
        failed_results = [r for r in self.current_batch_results if not r["success"]]

        # 计算总体积等统计信息
        total_volume = 0.0
        total_vertices = 0
        total_triangles = 0
        total_3d_area = 0.0
        total_projection_area = 0.0

        for result in successful_results:
            if result["analysis_result"]:
                analysis = result["analysis_result"]
                total_volume += analysis["volume_info"]["total_absolute_volume"]
                total_vertices += analysis["vertex_count"]
                total_triangles += analysis["triangle_count"]
                total_3d_area += analysis["surface_areas"]["total_3d_area"]
                total_projection_area += analysis["surface_areas"][
                    "total_projection_area"
                ]

        return {
            "total_files": len(self.current_batch_results),
            "successful_files": len(successful_results),
            "failed_files": len(failed_results),
            "success_rate": (
                (len(successful_results) / len(self.current_batch_results) * 100)
                if self.current_batch_results
                else 0
            ),
            "total_volume": total_volume,
            "total_vertices": total_vertices,
            "total_triangles": total_triangles,
            "total_3d_area": total_3d_area,
            "total_projection_area": total_projection_area,
            "failed_file_list": [
                os.path.basename(r["file_path"]) for r in failed_results
            ],
        }

    def get_processing_status(self) -> str:
        """获取当前处理状态"""
        return self.processing_status

    def get_output_directory(self) -> str:
        """获取输出目录路径"""
        return self.file_path_manager.get_output_directory()

    def open_output_directory(self) -> bool:
        """打开输出目录"""
        try:
            output_dir = self.get_output_directory()
            if os.path.exists(output_dir):
                os.startfile(output_dir)
                return True
            else:
                self._log("输出目录不存在")
                return False
        except Exception as e:
            self._log(f"无法打开输出目录: {str(e)}")
            return False

    def cleanup_output(self) -> int:
        """清理输出目录"""
        try:
            deleted_count = self.file_path_manager.cleanup_output_directory()
            self._log(f"已清理 {deleted_count} 个输出文件")
            return deleted_count
        except Exception as e:
            self._log(f"清理输出目录失败: {str(e)}")
            return 0

    def get_recent_results(self) -> List[Dict[str, Any]]:
        """获取最近的处理结果"""
        return self.current_batch_results.copy()

    def export_configuration(self, config_file_path: str) -> bool:
        """导出当前配置到文件"""
        try:
            import json

            config_data = {
                "files": [
                    {"file_path": config.file_path, "fixed_height": config.fixed_height}
                    for config in self.config_manager.file_configs
                ],
                "export_time": datetime.now().isoformat(),
                "project_config": {
                    "output_dir": self.file_path_manager.get_output_directory(),
                    "figure_dpi": self.config_manager.project_config.figure_dpi,
                    "figure_size": self.config_manager.project_config.figure_size,
                },
            }

            with open(config_file_path, "w", encoding="utf-8") as f:
                json.dump(config_data, f, indent=2, ensure_ascii=False)

            self._log(f"配置已导出到: {config_file_path}")
            return True

        except Exception as e:
            self._log(f"导出配置失败: {str(e)}")
            return False

    def import_configuration(self, config_file_path: str) -> bool:
        """从文件导入配置"""
        try:
            import json

            with open(config_file_path, "r", encoding="utf-8") as f:
                config_data = json.load(f)

            # 清空当前配置
            self.clear_files()

            # 导入文件配置
            imported_count = 0
            for file_config in config_data.get("files", []):
                file_path = file_config["file_path"]
                fixed_height = file_config["fixed_height"]

                if os.path.exists(file_path):
                    if self.add_file(file_path, fixed_height):
                        imported_count += 1
                else:
                    self._log(f"导入时跳过不存在的文件: {file_path}")

            self._log(f"成功导入 {imported_count} 个文件配置")
            return True

        except Exception as e:
            self._log(f"导入配置失败: {str(e)}")
            return False

    def _update_status(self, status: str):
        """更新处理状态"""
        self.processing_status = status
        if self.status_callback:
            self.status_callback(status)

    def _update_progress(self, current: int, total: int):
        """更新进度"""
        if self.progress_callback:
            self.progress_callback(current, total)

    def _log(self, message: str):
        """记录日志"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_message = f"[{timestamp}] {message}"
        self.log_messages.append(log_message)

        if self.log_callback:
            self.log_callback(log_message)

    def get_log_messages(self) -> List[str]:
        """获取所有日志消息"""
        return self.log_messages.copy()

    def clear_log(self):
        """清空日志"""
        self.log_messages.clear()


class DTMBatchProcessor:
    """DTM批量处理器 - 用于命令行批量处理"""

    def __init__(self, input_configs: List[Dict[str, Any]]):
        """
        初始化批量处理器

        Args:
            input_configs: 输入配置列表，格式为 [{'file_path': str, 'fixed_height': float}, ...]
        """
        self.controller = DTMController()
        self.input_configs = input_configs

    def run_batch_processing(self) -> Dict[str, Any]:
        """运行批量处理"""
        print("开始DTM批量验证处理...")

        # 添加文件配置
        for config in self.input_configs:
            file_path = config["file_path"]
            fixed_height = config["fixed_height"]

            if os.path.exists(file_path):
                self.controller.add_file(file_path, fixed_height)
                print(f"已添加: {os.path.basename(file_path)}")
            else:
                print(f"文件不存在，跳过: {file_path}")

        # 执行批量处理
        result = self.controller.process_batch()

        # 打印结果
        if result["success"]:
            summary = result["summary"]
            print(f"\n处理完成！")
            print(f"成功处理: {summary['successful_files']} 个文件")
            print(f"处理失败: {summary['failed_files']} 个文件")
            print(f"成功率: {summary['success_rate']:.1f}%")
            print(f"总体积: {summary['total_volume']:.4f} 立方米")
            print(f"输出目录: {self.controller.get_output_directory()}")
        else:
            print(f"批量处理失败: {result['error']}")

        return result


# 用于向后兼容的工厂函数
def create_dtm_controller(project_root: Optional[str] = None) -> DTMController:
    """创建DTM控制器实例"""
    return DTMController(project_root)


def create_batch_processor(input_configs: List[Dict[str, Any]]) -> DTMBatchProcessor:
    """创建批量处理器实例"""
    return DTMBatchProcessor(input_configs)
